package edu.ncu.utils;


/**
 * @author qp
 * @date 2019/4/16 14:05
 */
import edu.ncu.entity.Contact;
import edu.ncu.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Redis工具类
 */
@Component("redisUtil")
public class RedisUtil {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate ;
//    @Autowired
//    public RedisUtil(RedisTemplate redisTemplate) {
//        this.redisTemplate = redisTemplate;
//    }

    /**********************************off message list******************************/


    private String getOffMessageKey(int usedId) {
        return "off_message:"+usedId ;
    }

    /** userId作为离线消息的接收者
     * 根据usedId获取离线消息
     * @param usedId
     */
    public List<Contact> getOffMessageList(int usedId) {
        String key = getOffMessageKey(usedId) ;
        List<Contact> list = redisTemplate.opsForList().range(key,0,-1) ;
        return list ;
    }

    // 将所有离线消息改为在线消息(删除过长的离线消息)
    public void changeMessage(int userId) {
        String key = getOffMessageKey(userId) ;
        long size = redisTemplate.opsForList().size(key) ;
        //redisTemplate.opsForList().leftPop(key,size-10,10)
        for (int i=0;i<size-10;i++) {
            //
            redisTemplate.opsForList().leftPop(key) ;
        }
//        size = redisTemplate.opsForList().size(key) ;
//        for (int i=0;i<size-10;i++) {
//            // 通过下标取值
//            Contact c = (Contact) redisTemplate.opsForList().index(key,i) ;
//            if (c.getType() == 1) {
//                break;
//            } else {
//                c.setType(0);
//                redisTemplate.opsForList().set(key,i,c);
//            }
//        }
    }

    /**
     * right_push
     * 在线消息和离线消息，如果右边已经有在线消息了，那把所有的离线消息都改为在线消息
     * 添加离线消息
     * @param contact
     */
    public void addOffMessage(Contact contact) {
        int userId = contact.getReceiverId() ;
        String key = getOffMessageKey(userId) ;
        // 检查消息大小，如果超过指定大小则不会再接受消息

        redisTemplate.opsForList().rightPush(key,contact) ;
        if (contact.getType() == 0) {
            // 表示是离线消息
        } else {
            // 如果添加的是在线消息，则需要判断消息是否过大，过大再删除
            if (redisTemplate.opsForList().size(key) > 10) {
                // 删除消息 , 注意不能删除离线消息
                redisTemplate.opsForList().leftPop(key) ;
            }
        }
    }

    /**
     * 删除所有离线消息
     * @param usedId
     */
    public void removeAllOffMessage(int usedId) {
        String key = getOffMessageKey(usedId) ;
        redisTemplate.opsForList().remove(key,0,-1) ;
    }



    /**********************************message cache 消息缓存******************************/
    // userId 作为消息的接收者
    public String getMessageCacheKey(int userId) {
        return "message_cache:"+userId ;
    }
    // 控制消息缓存的大小不超过10
    public void addMessageCache(Contact contact) {
        int userId = contact.getReceiverId() ;
        String key = getMessageCacheKey(userId) ;
        redisTemplate.opsForList().rightPush(key,contact) ;
        if (redisTemplate.opsForList().size(key) > 10) {
            redisTemplate.opsForList().leftPop(key) ;
        }
    }

    /**********************************chat user list******************************/
    public String getChatUserListKey(int userId) {
        return "chat_user_list:"+userId ;
    }
    public void addChatUser(int userId, User chatUser) {
        // if (redisTemplate.opsForSet().)
        System.out.println(redisTemplate.opsForSet().isMember(getChatUserListKey(userId),chatUser));
        if (!redisTemplate.opsForSet().isMember(getChatUserListKey(userId),chatUser))  {
            redisTemplate.opsForSet().add(getChatUserListKey(userId),chatUser) ;
        }
        // redisTemplate.opsForList().rightPush(getChatUserListKey(userId),chatUser) ;
    }
    public void removeChatUser(int userId, User chatUser) {
        redisTemplate.opsForSet().remove(getChatUserListKey(userId),chatUser);
    }
    public Set<User> getChatUserList(int userId) {
        return redisTemplate.opsForSet().members(getChatUserListKey(userId)) ;
    }


    /**
     * 批量删除对应的value
     *
     * @param keys
     */
    public void remove(final String... keys) {
        for (String key : keys) {
            remove(key);
        }
    }

    /** publish1:great  表示指定publish的点赞数
     * publish1:great:user1 表示指定publish的指定用户点赞了1下
     * 批量删除key
     * String keys="publish1:great:*";   // 表示前缀
     * Set<String> keysList = stringRedisTemplate.keys(keys);
     *
     * keysList.forEach(i->{
     *     String key = i;
     *     String value=stringRedisTemplate.opsForValue().get(key);
     *     LogUtils.info("---------->"+value+"\n");
     * })
     * @param pattern
     */
    public void removePattern(final String pattern) {
        Set<Serializable> keys = redisTemplate.keys(pattern);
        if (keys.size() > 0)
            redisTemplate.delete(keys);
    }

    public Set<String> getPattern(final String pattern) {
        Set<String> keys =  stringRedisTemplate.keys(pattern) ;
        if (keys.size() > 0) {
            return keys ;
        }
        return null ;
    }

    public int size(String pattern) {
        return stringRedisTemplate.keys(pattern).size() ;
    }

    /**
     * 删除对应的value
     *
     * @param key
     */
    public void remove(final String key) {
        if (exists(key)) {
            redisTemplate.delete(key);
        }
    }

    /**
     * 判断缓存中是否有对应的value
     *
     * @param key
     * @return
     */
    public boolean exists(final String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 读取缓存
     *
     * @param key
     * @return
     */
    public Object get(final String key) {
        Object result = null;
        ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
        result = operations.get(key);
        return result;
    }


    /**
     * 普通缓存放入
     * @param key   键
     * @param value 值
     * @return true成功 false失败
     */

    public boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 普通缓存放入并设置时间
     * @param key   键
     * @param value 值
     * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
     * @return true成功 false 失败
     */

    public boolean set(String key, Object value, long time) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }



    /**
     * 获取list缓存的内容
     *
     * @param key   键
     * @param start 开始
     * @param end   结束 0 到 -1代表所有值
     */
    public<V> List<V> lGet(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取整个列表
     * @param key
     * @return
     */
    public<V> List<V> lGetAll(String key) {
        try {
            return redisTemplate.opsForList().range(key, 0, -1);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
//    public List<Object> lGet(String key ,int begin,int end) {
//
//    }


    /**
     * 获取list缓存的长度
     *
     * @param key 键
     */
    public long lSize(String key) {
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }


    /**
     * 通过索引 获取list中的值
     *
     * @param key   键
     * @param index 索引 index>=0时， 0 表头，1 第二个元素，依次类推；index<0时，-1，表尾，-2倒数第二个元素，依次类推
     */
    public Object lGetIndex(String key, long index) {
        try {
            return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     */
    public boolean rightPush(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    public boolean leftPush(String key, Object value) {
        try {
            redisTemplate.opsForList().leftPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    public boolean rightPop(String key) {
        try {
            redisTemplate.opsForList().rightPop(key);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    public boolean leftPop(String key) {
        try {
            redisTemplate.opsForList().leftPop(key);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }



    /**
     * 将list放入缓存
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     */
    public boolean lSet(String key, Object value, long time) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0)
                expire(key, time);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }


    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, List<Object> value) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }


    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     * @return
     */
    public boolean lSet(String key, List<Object> value, long time) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0)
                expire(key, time);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 根据索引修改list中的某条数据
     *
     * @param key   键
     * @param index 索引
     * @param value 值
     * @return
     */

    public boolean lUpdateIndex(String key, long index, Object value) {
        try {
            redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 移除N个值为value
     *
     * @param key   键
     * @param count 移除多少个
     * @param value 值
     * @return 移除的个数
     */

    public long lRemove(String key, long count, Object value) {
        try {
            Long remove = redisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    public long lRemoveAll(String key) {
        try {
            Long remove = redisTemplate.opsForList().remove(key, 0, -1);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }


    /****************************common**********************************/


    /**
     * 指定缓存失效时间
     * @param key  键
     * @param time 时间(秒)
     */
    public boolean expire(String key, long time) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


//    public void setRedisTemplate(RedisTemplate<Serializable, Object> redisTemplate) {
//        this.redisTemplate = redisTemplate;
//    }






}
